import { dialog, BrowserWindow, IpcMainInvokeEvent } from "electron"
import { readdir, stat, readFile, writeFile } from "fs/promises"
import { FSWatcher, watch } from "fs";
import { join } from "path";
import * as types from '../types'
import type { model } from "../src/types";

export async function selectFile(_: IpcMainInvokeEvent, type: number) {
    let { canceled, filePaths } = type == 0 ? await dialog.showOpenDialog({ properties: ['openDirectory', 'dontAddToRecent', 'noResolveAliases'] }) :
        await dialog.showOpenDialog({ properties: ['openFile', 'dontAddToRecent', 'noResolveAliases'], filters: [{ name: 'sql', extensions: ['sql'] }] })
    if (!canceled) {
        return filePaths[0]
    } else return null
}
export async function getProject(event: IpcMainInvokeEvent, path: string) {
    const res: types.fileInfo[] = []
    await traverseDirectory(path, res)
    return res
}
async function traverseDirectory(directory: string, data: types.fileInfo[]) {
    const files = await readdir(directory)
    for (const file of files) {
        const filePath = join(directory, file);
        if (file.endsWith('yaml')) {
            data.push({ name: file, path: filePath })
        } else {
            const stats = await stat(filePath);
            if (stats.isDirectory()) {
                await traverseDirectory(filePath, data);
            }
        }
    }

}
export async function getFile(event: IpcMainInvokeEvent, path: string) {
    return await readFile(path, { encoding: 'utf-8' })
}
let changedFile = ''
export async function saveFile(event: IpcMainInvokeEvent, path: string, content: string) {
    changedFile = path
    await writeFile(path, content, { encoding: 'utf-8' })
}
const regex = /TABLE public\.(\w+)\s*\(([\s\S]*?)\) TABLESPACE/g
export async function readDb(event: IpcMainInvokeEvent, path: string, exclude: string[]) {
    const data = await readFile(path, { encoding: 'utf-8' })
    let match: RegExpExecArray | null;
    let res: { [key: string]: model } = {}
    while ((match = regex.exec(data)) !== null) {
        if (isExclude(match[1], exclude)) continue
        let cols: model = {}
        match[2].trim().split('\n').forEach((v) => {
            const arr = v.trim().replace(/\s+/g, ' ').split(' ')
            if (arr[0] == 'CONSTRAINT') return
            switch (arr[1]) {
                case 'integer':
                    cols[arr[0]] = 'int'
                    break;
                case 'bigint':
                    cols[arr[0]] = 'long'
                    break;
                case 'boolean':
                    cols[arr[0]] = 'boolean'
                    break;
                default:
                    if (arr[1].startsWith('numeric')) {
                        cols[arr[0]] = 'decimal'
                    } else cols[arr[0]] = 'string'
                    break;
            }
        })
        res[match[1]] = cols
    }
    return res
}
function isExclude(name: string, exclude: string[]): boolean {
    for (const ex of exclude) {
        if (name.includes(ex)) return true
    }
    return false
}

let oriWatch: { path: string, watch: FSWatcher | null } = { path: '', watch: null }
export async function watchDir(event: IpcMainInvokeEvent, path: string) {
    if (oriWatch.path == path) return
    oriWatch.path = path
    if (oriWatch.watch != null) oriWatch.watch.close()
    oriWatch.watch = watch(path, (i, file) => {
        if (changedFile.endsWith(file!!)) {
            changedFile = ''
        } else {
            BrowserWindow.getAllWindows().forEach(v => {
                v.webContents.send('watch', path + '/' + file)
            })
        }
    })
}